﻿#include "Particle.h"

#include <chrono>
#include <cmath>
#include <numbers>
#include <iostream>

#include <vsg/all.h>

#include "DataSingleton.h"
#include "Particle.h"
#include "utilities.h"

vsg::ref_ptr<vsg::Node> Particle::getNode()
{
    using namespace vsg;
    m_matrixTransform = vsg::MatrixTransform::create();

    // create StateGroup as the root of the scene/command graph to hold the GraphicsProgram, and binding of Descriptors to decorate the whole graph
    auto scenegraph = vsg::StateGroup::create();


    // add transform to root of the scene graph
    scenegraph->addChild(m_matrixTransform);

    vec3 dx = { 0.5f, 0.0f, 0.0f };
    vec3 dy = { 0.0f, 0.5f, 0.0f };
    vec3 dz = { 0.0f, 0.0f, 0.5f };
    vec3 origin = { 0.0f, 0.0f, 0.0f };

    unsigned int num_columns = 20;
    unsigned int num_rows = 10;
    unsigned int num_vertices = num_columns * num_rows;
    unsigned int num_indices = (num_columns - 1) * (num_rows - 1) * 6;

    auto vertices = vec3Array::create(num_vertices);
    auto indices = ushortArray::create(num_indices);;
    m_colors = vsg::vec4Array::create(num_vertices, m_color);
    m_colors->properties.dataVariance = DYNAMIC_DATA_TRANSFER_AFTER_RECORD;

    for (unsigned int r = 0; r < num_rows; ++r)
    {
        float beta = ((float(r) / float(num_rows - 1)) - 0.5f) * PIf;
        float cos_beta = cosf(beta);
        vec3 dz_sin_beta = dz * sinf(beta);

        vec3 v = dy * cos_beta + dz_sin_beta;
        vec3 n = normalize(v);

        unsigned int left_i = r * num_columns;
        vertices->set(left_i, v + origin);

        unsigned int right_i = left_i + num_columns - 1;
        vertices->set(right_i, v + origin);

        for (unsigned int c = 1; c < num_columns - 1; ++c)
        {
            unsigned int vi = left_i + c;
            float alpha = (float(c) / float(num_columns - 1)) * 2.0f * PIf;
            v = dx * (-sinf(alpha) * cos_beta) + dy * (cosf(alpha) * cos_beta) + dz_sin_beta;
            n = normalize(v);
            vertices->set(vi, origin + v);
        }
    }

    unsigned int i = 0;
    for (unsigned int r = 0; r < num_rows - 1; ++r)
    {
        for (unsigned int c = 0; c < num_columns - 1; ++c)
        {
            unsigned lower = num_columns * r + c;
            unsigned upper = lower + num_columns;

            indices->set(i++, lower);
            indices->set(i++, lower + 1);
            indices->set(i++, upper);

            indices->set(i++, upper);
            indices->set(i++, lower + 1);
            indices->set(i++, upper + 1);
        }
    }

    // setup geometry
    auto drawCommands = vsg::Commands::create();
    drawCommands->addChild(vsg::BindVertexBuffers::create(0, vsg::DataList{ vertices, m_colors }));
    drawCommands->addChild(vsg::BindIndexBuffer::create(indices));
    drawCommands->addChild(vsg::DrawIndexed::create(num_indices, 1, 0, 0, 0));

    m_matrixTransform->addChild(drawCommands);

    return scenegraph;
}

void Particle::update(const std::chrono::nanoseconds& delt)
{
    if (isDone())
    {
        return;
    }

    m_duration += delt;

    if ((m_radius < 0.03 * m_A) && (m_duration.count() * 1e-9 > 1.f))
    {
        invalid();
        return;
    }

    double delt_seconds = delt.count() * 1e-9;
    // std::random_device rd;  // 将用于获得随机数引擎的种子
    // std::mt19937_64 gen(rd()); // 以 rd() 播种的标准 mersenne_twister_engine
    // std::uniform_real_distribution<double> dragCoefficient(-1, 1);
    double acceleration_x = -(m_dragCoefficient) * m_speed.x;
    double acceleration_y = -(m_dragCoefficient) * m_speed.y;
    double acceleration_z = -(m_dragCoefficient) * m_speed.z;

    // x = v0*t + 1/2*a*t^2
    double dx = m_speed.x * delt_seconds + 0.5 * acceleration_x * pow(delt_seconds, 2.0);
    double dy = m_speed.y * delt_seconds + 0.5 * acceleration_y * pow(delt_seconds, 2.0);
    double dz = m_speed.z * delt_seconds + 0.5 * acceleration_z * pow(delt_seconds, 2.0);

    m_pos.x += dx;
    m_pos.y += dy;
    m_pos.z += dz;

    // v = v0 + a*t
    m_speed.x += acceleration_x * delt_seconds;
    m_speed.y += acceleration_y * delt_seconds;
    m_speed.z += acceleration_z * delt_seconds;

    double t = m_duration.count() * 1e-9;

    // 以半径的变化设定颜色饱和度和亮度
    double A = m_A * 1.0f / (sqrt(2. * std::numbers::pi) * m_theta); // 正态分布最大值
    double left_value = 0.5;
    double right_value = 1;
    double span = right_value - left_value;
    double hsvRatio = m_radius / A;
    double deltH = DataSingleton::instance()->h_k * t;
    vsg::dvec3 hsv = ColorToHSV(m_color);
    hsv.x += deltH;
    hsv.y = left_value + span * hsvRatio;
    hsv.z = left_value + span * hsvRatio;
    m_color = ColorFromHSV(hsv.x, hsv.y, hsv.z);
    for (auto& color : *m_colors)
    {
        color.set(m_color.r, m_color.g, m_color.b, m_color.a);
    }
    m_colors->dirty();

    // 半径以正态方程变化
    m_radius = A * exp(-pow(t - m_mu, 2.0) / (2.0 * pow(m_theta, 2.0)));

    m_matrixTransform->matrix = vsg::translate(m_pos) * vsg::scale(m_radius, m_radius, m_radius);
}

void Particle::activate()
{
    m_state = ParticleState::Flying;
    m_duration -= m_duration;

    // y = A*a**2
    // y = A*(1+D*deltT)**x
    // speed = initSpeed * (1+dragCoefficeint*deltT)**n
    // n = log_(1+deltT)(y/A)
    // 根据初始速度计算出速度接近于0所需的时间，设定为正态方程的均值，以实现在烟花粒子近乎静止时，烟花粒子的半径达到最大，亮度最高
    double deltT = 0.001;
    double speedEnd = 7;
    double D = -m_dragCoefficient;
    double initSpeed = length(m_speed);
    double a = 1 + D * deltT;
    double n = log(speedEnd / initSpeed) / log(a);
    double t = n * deltT * 2;
    m_mu = t;
}

void Particle::invalid()
{
    m_state = ParticleState::Done;
}


